﻿/*
 * Rappelz: Endless Odyssey - The first free open source Rappelz server emulator
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.Network;
using System.Data.Common;
using System.Data;
using Rappelz.GameServer.Network.GameClient;

namespace Rappelz.GameServer.Database
{
    /// <summary>
    /// DB_CharacterList (smp_read_character_list, smp_read_item_equip_info)
    /// </summary>
    public class DB_CharacterList : IDBProc
    {
        private int m_nAccountId;
        private TCPConnection m_client;
        public BaseObject m_CBObject = null;

        private enum DBFields : int
        {
            AccountId = 0,
            Name,
            Race,
            Sex,
            Level,
            JobLevel,
            Exp,
            Hp,
            Mp,
            Job,
            Permission,
            SkinColor,
            Model00,
            Model01,
            Model02,
            Model03,
            Model04,
            HairDye,
            HairCut,
            Unk1,
            Face,
            Permission2,
            CreateTime,
            DeleteTime,
            LoginTime,
            LoginCount,
            LogoutTime,
            PlayTime,
        }

        public void SetCB(BaseObject obj)
        {
            m_CBObject = obj;
        }

        public void RunCB()
        {
            if (m_CBObject != null)
                m_CBObject.onEndQuery();
        }

        public DB_CharacterList(TCPConnection client, int nAccountId)
        {
            m_client = client;
            m_nAccountId = nAccountId;
        }

        public bool onProcess()
        {
            DbConnection conn = GameDBManager.Instance.CreateConnection();
            DbCommand cmd = conn.CreateCommand();

            cmd.CommandText = "smp_read_character_list";
            cmd.CommandType = CommandType.StoredProcedure;

            DbParameter account = GameDBManager.Instance.CreateParameter("IN_ACCOUNT_ID");
            account.DbType = DbType.Int32;
            account.Direction = ParameterDirection.Input;
            account.Value = m_nAccountId;
            cmd.Parameters.Add(account);
            conn.Open();
            cmd.Prepare();

            ushort count = 0;
            ushort last_login = 0;
            DateTime logoutTime = new DateTime(1,1,1);
            List<LobbyCharacterInfo> chars = new List<LobbyCharacterInfo>();
            try
            {
                ushort idx = 0;
                DbDataReaderTypeCastHelper dr = new DbDataReaderTypeCastHelper(cmd.ExecuteReader());
                while (dr.Read())
                {
                    LobbyCharacterInfo info = new LobbyCharacterInfo();

                    int sid = dr.GetInt32((int)DBFields.AccountId);
                    info.name = dr.GetString((int)DBFields.Name);
                    info.race = dr.GetInt32((int)DBFields.Race);
                    info.sex = dr.GetInt32((int)DBFields.Sex);
                    info.level = dr.GetInt32((int)DBFields.Level);
                    info.job_level = dr.GetInt32((int)DBFields.JobLevel);
                    info.exp = (int)dr.GetInt64((int)DBFields.Exp);
                    info.hp = dr.GetInt32((int)DBFields.Hp);
                    info.mp = dr.GetInt32((int)DBFields.Mp);
                    info.job = dr.GetInt32((int)DBFields.Job);
                    info.permission = dr.GetInt32((int)DBFields.Permission);
                    info.skin_color = (uint)dr.GetInt32((int)DBFields.SkinColor);
                    info.model_id[0] = dr.GetInt32((int)DBFields.Model00);
                    info.model_id[1] = dr.GetInt32((int)DBFields.Model01);
                    info.model_id[2] = dr.GetInt32((int)DBFields.Model02);
                    info.model_id[3] = dr.GetInt32((int)DBFields.Model03);
                    info.model_id[4] = dr.GetInt32((int)DBFields.Model04);
                    info.hair_color_index = dr.GetInt32((int)DBFields.HairDye); // hair_color_index
                    info.hair_color_rgb = dr.GetInt32((int)DBFields.HairCut); // hair_color_rgb
                    info.hide_equip_flag = dr.GetInt32((int)DBFields.Unk1); // hide_equip_flag
                    info.texture_id = dr.GetInt32((int)DBFields.Face); // texture_id
                    info.permission = dr.GetInt32((int)DBFields.Permission2);
                    info.szCreateTime = dr.GetString((int)DBFields.CreateTime);
                    info.szDeleteTime = dr.GetString((int)DBFields.DeleteTime);
                    DateTime dtLogout = dr.GetDateTime((int)DBFields.LogoutTime);
                    if (logoutTime < dtLogout)
                    {
                        logoutTime = dtLogout;
                        last_login = idx;
                    }

                    DbConnection conn2 = GameDBManager.Instance.CreateConnection();
                    DbCommand cmd2 = conn2.CreateCommand();

                    cmd2.CommandText = "smp_read_item_equip_info";
                    cmd2.CommandType = CommandType.StoredProcedure;

                    DbParameter acctid = GameDBManager.Instance.CreateParameter("IN_SID");
                    acctid.DbType = DbType.Int32;
                    acctid.Direction = ParameterDirection.Input;
                    acctid.Value = sid;
                    cmd2.Parameters.Add(acctid);
                    conn2.Open();
                    cmd2.Prepare();
                    idx++;

                    DbDataReaderTypeCastHelper dr2 = new DbDataReaderTypeCastHelper(cmd2.ExecuteReader());

                    while (dr2.Read())
                    {
                        // SELECT wear_info, code, enhance, level, elemental_effect_type, elemental_effect_expire_time, appearance_code
                        int wear_info = dr2.GetInt32(0);
                        info.wear_info[wear_info] = dr2.GetInt32(1);
                        info.wear_item_enhance_info[wear_info] = dr2.GetInt32(2);
                        info.wear_item_level_info[wear_info] = dr2.GetInt32(3);
                        info.wear_item_elemental_type[wear_info] = dr2.GetByte(4);
                        info.wear_appearance_code[wear_info] = dr2.GetInt32(6);
                    }

                    chars.Add(info);

                    count++;
                }

            }
            catch (System.Exception ex)
            {
                Globals.Log.Error("Exception: {0}", ex);
            }
            conn.Close();

            PacketOut o = new PacketOut((ushort)ClientOutPackets.CharacterListResult);
            o.WriteUInt32((uint)Globals.GetUnixTimestampUInt64()); // current_server_time
            o.WriteShort(last_login); // last_login_index
            o.WriteShort(count); // count

            lock(m_client.Tag)
            {
                m_client.Tag.vCharacterNameList.Clear();
                foreach (LobbyCharacterInfo info in chars)
                {
                    m_client.Tag.vCharacterNameList.Add(info.name);
                    o.WriteInt32(info.sex);
                    o.WriteInt32(info.race);
                    for (int i = 0; i < 5; ++i)
                    {
                        o.WriteInt32(info.model_id[i]);
                    }

                    o.WriteInt32(info.hair_color_index);
                    o.WriteInt32(info.hair_color_rgb);
                    o.WriteInt32(info.hide_equip_flag);
                    o.WriteInt32(info.texture_id);

                    for (int i = 0; i < 24; ++i)
                    {
                        o.WriteInt32(info.wear_info[i]);
                    }
                    // end of model_info

                    o.WriteInt32(info.level);
                    o.WriteInt32(info.job);
                    o.WriteInt32(info.job_level);
                    o.WriteInt32(info.exp);
                    o.WriteInt32(info.hp);

                    o.WriteInt32(info.mp);
                    o.WriteInt32(info.permission);
                    o.WriteByte((byte)(info.is_banned ? 1 : 0));
                    o.FillString(info.name, 19);
                    o.WriteUInt32(info.skin_color);
                    o.FillString(info.szCreateTime, 30);
                    o.FillString(info.szDeleteTime, 30);
                    for (int i = 0; i < 24; ++i)
                    {
                        o.WriteInt32(info.wear_item_enhance_info[i]);
                    }
                    for (int i = 0; i < 24; ++i)
                    {
                        o.WriteInt32(info.wear_item_level_info[i]);
                    }
                    for (int i = 0; i < 24; ++i)
                    {
                        o.WriteByte(info.wear_item_elemental_type[i]);
                    }
                    for (int i = 0; i < 24; ++i)
                    {
                        o.WriteInt32(info.wear_appearance_code[i]);
                    }
                }
            }

            m_client.SendTCP(o);

            return true;
        }
    }
}
